液晶表示器で文字表示してみよう!−−その1
(8ビットインターフェースデータ長の場合)

液晶表示器は、インストラクションというデータコードを使って制御することができます。液晶表示器は文字を表示するだけでなく、インストラクションによりカーソルを表示したり、あるいは文字をブリンク(点滅)することもできます。ここでは、PIC16F877を使って実際に液晶表示器に文字を表示させてみます。まずはインターフェースデータ長8ビットの場合です。


<項目>ハード側の接続
図1に液晶表示器とPIC間の接続回路例を示します。図1(a)はSC1602BSLB(16文字×2行)、(b)はSC2004C(20文字×4行)のSUNLIKE社製の液晶表示器を使いました。液晶表示器のコネクタ・ピン配置の項目を参照して確実に接続してください。
詳細はこちら→コネクタ・ピン配置について
特に電源端子ですが、同じSUNLIKE社製でありながら、VDDとVSSだけが逆になっています。もしも間違えると壊れる可能性大です。差し替えの際には十分注意してください。また、コントラスト調整電源端子(Vo)ですが、10kΩの可変抵抗器で0〜5Vの電圧を供給しています。Vo=0V(VSS)で最も濃くなります。可変抵抗器がなければ、とりあえずVo端子はVSSに接続しておいてください。

液晶表示器(16文字×2行)とPIC間の接続(8ビット・インターフェースデータ長の場合)
図1(a).液晶表示器(16文字×2行)とPIC間の接続
(8ビット・インターフェースデータ長の場合)


液晶表示器(20文字×4行)とPIC間の接続(8ビット・インターフェースデータ長の場合)
図1(b).液晶表示器(20文字×4行)とPIC間の接続
(8ビット・インターフェースデータ長の場合)

液晶表示器との接続には、図2のようにL字型のコネクタを使い、20文字×4行の液晶表示器では、1ピンと2ピンを入れ替えて半田付けしました。すなわち、16文字×2行の液晶表示器との接続に合わせました。これで、電源端子の位置関係(VDDとVSSだけが逆)を気にせずに使うことができます。図3は、液晶表示器をPICターゲットボートと組み合わせてプログラムの動作確認をしているところです。(注)図3の写真は、ちょうど16文字×2行の液晶表示器に接続していますが、コネクタ部は簡単に脱着できるので、20文字×4行の液晶表示器にもすぐにつなぐことができて便利です。また、コネクタにつなげるケーブルも統一することができ、誤接続する心配はありません。

液晶表示器(20文字×4行)の接続コネクタ部分の写真 PICターゲットボードを使った液晶表示プログラムの動作確認
図2.液晶表示器(20文字×4行)の
接続コネクタ部分の写真
(1ピンと2ピンを入れ替えて接続)
図3.PICターゲットボードを使った
液晶表示プログラムの動作確認
 



<項目>液晶表示動作の確認プログラム(1)
(8ビット・インターフェースデータ長の場合)


図3に液晶表示動作の確認プログラムのフローチャートを示します。
プログラムの解説については、「プログラムの説明」の項をご参照ください。

液晶表示動作の確認プログラム(1) フローチャート
液晶表示動作の確認プログラム(1) フローチャート
液晶表示動作の確認プログラム(1) フローチャート
液晶表示動作の確認プログラム(1) フローチャート
図3−1.液晶表示動作の確認プログラム(1)
フローチャート


LCD・コマンド出力サブルーチンのフローチャート LCD・文字データ出力サブルーチンのフローチャート
図3−2.LCD・コマンド出力
サブルーチンのフローチャート


図3−3.LCD・文字データ出力
サブルーチンのフローチャート


LCD・初期化サブルーチンのフローチャート
LCD・初期化サブルーチンのフローチャート
LCD・ビジーチェックサブルーチンのフローチャート
LCD・ビジーチェックサブルーチンのフローチャート
図3−5.LCD・ビジーチェック
サブルーチンのフローチャート




図3−4.LCD・初期化
サブルーチンのフローチャート


(注)以下に示すプログラムには、ホームページ画面作成の都合上、空白として全角文字のスペースなどが挿入されています。したがって、下記プログラムリストをそのままコピーしてMPLABのソースファイルとされた場合には、エラーとなることがあります。

→ここをクリックして、下記のプログラムをダウンロードするようにしてください。
  <ダウンロードする>ファイル名:「lcd_1.asm」 サイズ8.12kバイト

→ここをクリックして、下記のオブジェクトファイルをダウンロードするようにしてください。
  <ダウンロードする>ファイル名:「lcd_1.hex」 サイズ913バイト

;***********************************************************
;
; 液晶表示器(LCD)テストプログラム(1)
; (8ビットインターフェースデータ長の場合)
;
; LCDの DB7〜DB0端子は、それぞれ PIC のRB0〜RB7端子に接続
; LCDの RS,R/W,E端子は、それぞれ PIC のRA2,RA1,RA0端子に接続
;
; テスト表示例は、下記の文字を表示するものとする。
;
; SPECTRUMホームへ゜ーシ゛
; 0123456789ABCDEF
;
;***********************************************************
    LIST   P=PIC16F877
    INCLUDE  P16F877.INC
;(1)プロセッサの種別指定
;(2)インクルードファイルの指定
;***********************************************************
; 変数定義とレジスタ割付
;***********************************************************
COUNT  EQU 20H
COUNT1 EQU 21H
COUNT2 EQU 22H
COUNT3 EQU 23H
COUNT4 EQU 24H
DPDT  EQU 25H
POINT  EQU 26H

RS   SET 2
RW   SET 1
E    SET 0

BUSY_F SET 7

    ORG 0
;(3)ループカウンタ
;   ループカウンタ1
;   ループカウンタ2
;   ループカウンタ3
;   ループカウンタ4
;   一時保存データ
;   テーブルポインタ
;
;   LCD レジスタ選択信号のビット番号
;   LCD 読み出し/書き込み選択信号のビット番号
;   LCD 動作起動信号のビット番号
;
;   LCD ビジーフラグのビット番号
;
;(4)プログラムの開始番地の指定
;***********************************************************
; 入出力ピン初期化
;***********************************************************
    BSF    STATUS,RP0
    MOVLW   B'00000110'
    MOVWF   ADCON1
    MOVLW   B'11111000'
    MOVWF   TRISA
    CLRF   TRISB
    BCF    STATUS,RP0
;(5)Bank 1 へ切替
;(6)全PortA,E ディジタル入出力に設定
;   ADCON1レジスタの設定
;(7)RA2,RA1,RA0を出力モードに
;   PortA を設定
;(8)全PortB 出力モードに設定
;(9)Bank 0 へ戻す
;***********************************************************
; メインプログラム
;***********************************************************
START
    CALL   LCD_INI

    CALL   LCD_BUSY
    MOVLW   B'00001110'
    CALL   LCD_CMD
    CALL   TIME1S
;
;(10)液晶表示器の初期化サブルーチンへ
;
;(11)BFチェック
;(12)表示ON、カーソルON
;(13)液晶表示器へコマンド出力
;(14)WAIT(1秒)

TEXT_OUT1
    CLRF   POINT
ROW_1
    MOVF   POINT,W
    CALL   TABLE
    ADDLW   0
    BTFSC   STATUS,Z
    GOTO   TEXT_OUT2
    CALL   LCD_DATA
    CALL   TIME1S
    INCF   POINT,F
    GOTO   ROW_1


;(15)テーブルポインタのリセット
;(16)1行目のテキストデータ表示
;(17)テーブルポインタの値をWregへロードする(OFFSET)
;(18)テキストデータの読み込みサブルーチンへ
;(19)Wregレジスタに0を加算する
;   演算結果がゼロかチェック(テキストデータは「0」?)
;   テキストデータが終了のとき TEXT_OUT2へジャンプ
;   テキストデータをLCD出力するためサブルーチンへ
;(20)WAIT(1秒)
;(21)テーブルポインタ +1
;(22)ROW_1 のラベルへ戻り繰り返す

TEXT_OUT2
    INCF   POINT,F
    MOVLW   B'11000000'
    CALL   LCD_CMD
    CALL   TIME1S


;(23)テーブルポインタ +1
;(24)カーソルが2行目にくるようにアドレスセット
;(25)液晶表示器へコマンド出力
;(26)WAIT(1秒)

ROW_2
    MOVF   POINT,W
    CALL   TABLE
    ADDLW   0
    BTFSC   STATUS,Z
    GOTO   TEXT_CLEAR
    CALL   LCD_DATA
    CALL   TIME1S
    INCF   POINT,F
    GOTO   ROW_2

;(27)2行目のテキストデータ表示
;(28)テーブルポインタの値をWregへロードする(OFFSET)
;(29)テキストデータの読み込みサブルーチンへ
;(30)Wregレジスタに0を加算する
;   演算結果がゼロかチェック(テキストデータは「0」?)
;   テキストデータが終了のとき TEXT_CLEARへジャンプ
;   テキストデータをLCD出力するためサブルーチンへ
;(31)WAIT(1秒)
;(32)テーブルポインタ +1
;(33)ROW_2 のラベルへ戻り繰り返す

TEXT_CLEAR
    MOVLW   B'00000001'
    CALL   LCD_CMD
    CALL   TIME1S
;
    GOTO   TEXT_OUT1


;(34)表示クリア
;(35)液晶表示器へコマンド出力
;(36)WAIT(1秒)

;(37)テキスト文字を繰り返し表示する

TABLE
    ADDWF   PCL,F
    DT "SPECTRUMホームページ",0 
    DT "0123456789ABCDEF",0 

;
;(38)PC+OFFSET
;
;   TABLEの定義(PC+OFFSET相当のデータを持って戻る)
;***********************************************************
; 液晶表示器の初期化サブルーチン    (39)
;***********************************************************
LCD_INI
    CALL   TIME10M
    CALL   TIME10M
    MOVLW   B'00110000'
    CALL   LCD_CMD

    CALL   TIME10M
    MOVLW   B'00110000'
    CALL   LCD_CMD

    CALL   TIME100
    MOVLW   B'00110000'
    CALL   LCD_CMD

    CALL   TIME100
    MOVLW   B'00111000'
    CALL   LCD_CMD

    CALL   LCD_BUSY
    MOVLW   B'00001000'
    CALL   LCD_CMD

    CALL   LCD_BUSY
    MOVLW   B'00000001'
    CALL   LCD_CMD

    CALL   LCD_BUSY
    MOVLW   B'00000110'

    CALL   LCD_CMD

    RETURN

;(40)WAIT(10ms)
;   WAIT(10ms) 10ms×2=20msを確保(15ms以上)
;(41)ファンクションセット(8bitモードに設定)
;(42)液晶表示器へコマンド出力

;(43)WAIT(10ms)を確保(4.1ms以上)
;(44)ファンクションセット(8bitモードに設定)
;(45)液晶表示器へコマンド出力

;(46)WAIT(100μs)
;(47)ファンクションセット(8bitモードに設定)
;(48)液晶表示器へコマンド出力

;(49)WAIT(100μs)
;(50)ファンクションセット(8bitモード,1/16デューティ,5×7ドット)
;(51)液晶表示器へコマンド出力

;(52)ここからBFチェックができます
;(53)表示オフ
;(54)液晶表示器へコマンド出力

;(55)BFチェック
;(56)表示クリア
;(57)液晶表示器へコマンド出力

;(58)BFチェック
;(59)エントリーモードセット
;   (アドレスを+1し、カーソルは右移動,表示シフトはしない)
;(60)液晶表示器へコマンド出力


;***********************************************************
; 液晶表示器へコマンドを出力するサブルーチン
;***********************************************************
LCD_CMD
    MOVWF   PORTB
    BCF    PORTA,RW
    BCF    PORTA,RS
    BSF    PORTA,E
    NOP
    BCF    PORTA,E
    RETURN
;(61)液晶表示器へコマンドを出力するサブルーチン
;(62)DB0〜DB7(データバスの設定)
;(63)R/W = 0 (書き込みモードに設定)
;(64)RS = 0 (コマンドモードに設定)
;(65)E = 1 (動作起動信号の設定:Hでストローブ)
;(66)Eのパルス幅を220ns以上確保するためのダミー命令
;(67)E = 0 (動作起動信号の設定:Lに戻す)

;***********************************************************
; 液晶表示器へデータを出力するサブルーチン
;***********************************************************
LCD_DATA
    MOVWF   PORTB
    BCF    PORTA,RW
    BSF    PORTA,RS
    BSF    PORTA,E
    NOP
    BCF    PORTA,E
    RETURN
;(68)液晶表示器へデータを出力するサブルーチン
;(69)DB0〜DB7(データバスの設定)
;(70)R/W = 0 (書き込みモードに設定)
;(71)RS = 1 (データモードに設定)
;(72)E = 1 (動作起動信号の設定:Hでストローブ)
;(73)Eのパルス幅を220ns以上確保するためのダミー命令
;(74)E = 0 (動作起動信号の設定:Lに戻す)
;
;***********************************************************
; ビジーチェック(BF)を行うサブルーチン
;***********************************************************
LCD_BUSY
    BSF    STATUS,RP0
    MOVLW   0FFH
    MOVWF   TRISB
    BCF    STATUS,RP0
    BCF    PORTA,RS
    BSF    PORTA,RW
    BSF    PORTA,E
    MOVF   PORTB,W
    BCF    PORTA,E
    MOVWF   DPDT
    BTFSC   DPDT,BUSY_F
    GOTO   LCD_BUSY

    BCF    PORTA,RW
    BSF    STATUS,RP0
    MOVLW   0H
    MOVWF   TRISB
    BCF    STATUS,RP0
    RETURN
;(75)ビジーチェック(BF)を行うサブルーチン
;(76)Bank 1 へ切替
;(77)入力モードに
;   PortB を設定
;(78)Bank 0 へ戻す
;(79)RS = 0 (コマンドモードに設定)
;(80)R/W = 1 (読み込みモードに設定)
;(81)E = 1 (動作起動信号の設定:Hでストローブ)
;(82)DDRAMからのデータの読み出し
;(83)E = 0 (動作起動信号の設定:Lに戻す)
;(84)読み込みデータをレジスタファイルに一時保存
;(85)ビジーフラグのチェック(読み込みデータの7ビット目)
;   BUSY_F=1のときLCD_BUSY間をループする
;   BUSY_F=0のときループを抜ける
;(86)R/W = 0 (書き込みモードに設定)
;(87)Bank 1 へ切替
;(88)出力モードに
;   PortB を設定
;(89)Bank 0 へ戻す
;
;***********************************************************
;遅延サブルーチン
;***********************************************************
;100μs遅延サブルーチン(20MHzクロック時)
;・・・・・ 別記プログラムリスト参照・・・・・
;
;10ms遅延サブルーチン(20MHzクロック時)
;・・・・・ 別記プログラムリスト参照・・・・・
;
;1s遅延サブルーチン(20MHzクロック時)
;・・・・・ 別記プログラムリスト参照・・・・・

    END


【プログラムの説明】ここがポイント
このプログラムについて、順を追って解説を加えておきましょう。

(1)プロセッサの種別指定
定義の仕方は「PROCESSOR」か「LIST」命令を使って設定します。ここで指定するプロセッサ名称は、パッケージの種類を示すサフィックス(最後の英記号の部分)は不要です。

   PROCESSOR  PIC16F877
    または
   LIST  P=PIC16F877

(2)標準ヘッダーファイルのインクルード
標準ヘッダーファイルとは、各プロセッサが持っているSFR(Special Function Register)をラベル(記号)で使える

ため、ラベルとハードウェアの場所とを定義しているファイルです。標準ヘッダーファイルは 「プロセッサ名.INC」というファイル名で統一されて、MPLABのディレクトリに格納されています。従って、これのインクルード方法は下記のようにして行います。
一度、参考までに標準ヘッダーファイルの内容をエディタ等で見ておくことをお勧めします。

   INCLUDE    P16F877.INC
    または
   #INCLUDE   P16F877.INC

(3)変数定義とレジスタ割付
レジスタファイルアドレスを指定するときに、アドレス数値を直接指定することもできますが、数値だけでは間違いも多く、プログラム自身も分かりにくくなってしまいます。そこで、EQU命令などを使ってラベルを設定し変数を定義します。レジスタファイルアドレスは、7ビットあるので、00〜7Fまで最大128個のレジスタが指定できますが、実際に物理的に実装されて汎用的に使用できるレジスタ数はデバイスによって異なっていますので注意が必要です。
PIC16F877の汎用レジスタのアドレスは、20H〜7FH
となっていますので、20H以降のアドレスに割り付けます。

(4)プログラムの開始番地の指定
「ORG」はプログラムの開始番地を指定する擬似命令で、ORG以下の実際のプログラム命令が格納されるプログラムメモリ内の位置(アドレス)を指定します。

   ORG  0  ;0番地から格納することを示します。

コンピュータは一般に電源投入時やリセットをすると必ず0番地からスタートするようになっているので、0番地には必ず命令があることが必要です。

(5)Bank 1 へ切替
PICには各種の動作モードを設定するための Special Register と呼ばれるものが用意されています。PICを動作させるためには、まずこのSpecial Registerの設定から始めます。そしてそれらは全て、Register File と呼ぶメモリとして用意されています。その Register Fileは Bank0, Bank1, Bank2, Bank3 とよばれるアドレス空間をもっているため、多少アクセスの仕方が面倒です。つまりRESET後の通常はBank0となっているので、Bank1側のレジスタにアクセスするときはBankの切替えをしてからとなります。またBank0とBank1に同じ物があるときにはどちらでも同じ様に使えます。
Bank1へ切り替える方法ですが、「STATUS」レジスタにある2ビットのRP0、RP1を変えてBankを指定します。デフォルトは、Bank0です。表1にBankとRP1,RP0ビットとの関係を示します。Bank1へ切り替えるためには、RP0ビットを「1」にします。(RP1はデフォルトで「0」なので変える必要はない。)

 BSF    STATUS,RP0
「STATUS」レジスタのRP0ビットを「1」にする。

表1.BankとRP1,RP0ビットとの関係
Bank RP1 RP0


(6)全PortA,E ディジタル入出力に設定
   ADCON1レジスタの設定

ここがポイント
RA,REポートをディジタル入出力ポートとして使用するためには、ADCON1レジスタの設定が必要

RA,REポートをディジタル入出力ポートとして使用するためには、ADCON1レジスタの設定が必要になります。PICのリセット後は、RA,REポートがA/D変換の入力ポートになっているからです。ADCON1レジスタの3〜0ビット(PCFGx)の設定内容より決定します。ここでは、LCDモジュールに接続されているRA0,RA1,RA2の3端子がディジタル入出力ポートに設定される条件を見つけます。PCFGx=「0110」 または 「0111」 のとき、RA0,RA1,RA2の3端子がディジタル入出力ポートになることが分かります。

ADCON1レジスタの設定内容の詳細は、こちらをご覧ください。→ADCON1レジスタの設定内容について

なお、ここではADCON1レジスタの7〜4ビットは、簡単のためとりあえず「0」とでもしておき、またPCFGx=「0110」とすることで、すなわち、「ADCON1→B’00000110’ (6H)」に設定することで、RA0,RA1,RA2の3端子をディジタル入出力ポートとして使用することができます。

(7)RA2,RA1,RA0を出力モードにPortA を設定
TRISAレジスタの下位3ビットを、”0”に設定することで、RA2,RA1,RA0ポートを出力モードとします。その他のRAポートは使用しませんので、”1”として入力モードにしておきます。もちろんRA全ポートを出力モードに設定しておいても構いませんが、実機を使ってデバッグする際に使用しないポートが出力になっていたりすると、思わぬショートで過大な電流が流れることもあり、安全面から考えると入力モードにしておく方がよいです。

(8)PORTB 全ポートを出力に設定
TRISBレジスタを、CLRF(fレジスタをゼロクリアする命令)で出力設定とします。

 CLRF   TRISB
「TRISBレジスタをゼロクリアする。すなわち、PORTB全ポートを出力に設定する」

(9)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。Bank1へ切り替えるためには、RP0ビットを「0」にします。(RP1はデフォルトで「0」なので変える必要はない。)

BCF    STATUS,RP0
「STATUS」レジスタのRP0ビットを「0」にする。すなわち、Bank0に戻す。」

(10)液晶表示器の初期化サブルーチンへ
液晶表示器を使用する前に、初期化しておきます。ここでは、LCD_INIというラベルの付いたサブルーチンへジャンプします。

(11)BFチェック
液晶表示器の初期化が完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSYというラベルの付いたサブルーチンへジャンプします。

(12)表示ON、カーソルON
液晶表示器の初期化後は、表示がOFFとなっているため、表示やカーソルの有無指定をします。
このインストラクションの詳細については、表示オン/オフコントロールを参照

(13)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(14)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(15)テーブルポインタのリセット
POINTという変数を使い、表示させる文字列テーブルの文字位置を指し示すようにしました。最初の文字から表示させるため、ここでPOINT変数の値をクリアしておきます。

(16)1行目のテキストデータ表示
ここのラベル「ROW_1」以降のルーチンにより、液晶表示器の1行目にテキストを表示します。

(17)テーブルポインタの値をWregへロードする
文字列テーブルのポインタ値をワーキングレジスタへロードします。

(18)テキストデータの読み込みサブルーチンへ
表示させる文字列テーブル TABLEというラベルの付いたサブルーチンへジャンプします。

(19)Wregレジスタに0を加算する
   演算結果がゼロかチェック(テキストデータは「0」?)
   テキストデータが終了のとき TEXT_OUT2へジャンプ
   テキストデータがあればLCD出力するためのサブルーチンへ

テキストデータの読み込みサブルーチンから戻ってきたときに、ワーキングレジスタに文字コードを入れて戻ってきます。ただし、文字列の終了を判断するのに、”0”を使っています。ここでワーキングレジスタの内容が”0”であれば、演算結果が”0”になるのでゼロフラグが立ちます。一方、ワーキングレジスタの内容に文字コードが入っていれば、”0”を加算しても文字コードの値は変化しません。すなわち、表示する文字があればLCD_DATAというサブルーチンへジャンプして表示し、終了すれば次の段階のTEXT_OUT2へジャンプする条件分岐を行っています。

(20)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(21)テーブルポインタ +1
次の文字表示を行うためテーブルポインタの値を+1します。テーブルポインタの値は、プログラムカウンタにテーブルポインタの値(OFFSET分)を足し合わせることで、表示文字が記載されたテーブルの位置関係を指し示すようになっています。

(22)ROW_1 のラベルへ戻り繰り返す
次の文字表示を行うため、ROW_1 のラベルへ戻り繰り返します。

(23)テーブルポインタ +1
2行目からの文字表示を行うためテーブルポインタの値を+1します。

(24)カーソルが2行目にくるようにアドレスセット
カーソルを2行目の先頭に来るように液晶表示器のアドレスをセットします。
アドレスの値は、40になります。詳細は液晶表示器の内部アドレスを参照してください。またアドレスセットのインストラクションについては、DDRAMアドレスセットを参照してください。 ここでは、B’11000000’になります。

(25)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(26)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(27)2行目のテキストデータ表示
ここのラベル「ROW_2」以降のルーチンにより、液晶表示器の2行目にテキストを表示します。

(28)テーブルポインタの値をWregへロードする
文字列テーブルのポインタ値をワーキングレジスタへロードします。

(29)テキストデータの読み込みサブルーチンへ
表示させる文字列テーブル TABLEというラベルの付いたサブルーチンへジャンプします。

(30)Wregレジスタに0を加算する
   演算結果がゼロかチェック(テキストデータは「0」?)
   テキストデータが終了のとき TEXT_CLEARへジャンプ
   テキストデータがあればLCD出力するためのサブルーチンへ

テキストデータの読み込みサブルーチンから戻ってきたときに、ワーキングレジスタに文字コードを入れて戻ってきます。ただし、文字列の終了を判断するのに、”0”を使っています。ここでワーキングレジスタの内容が”0”であれば、演算結果が”0”になるのでゼロフラグが立ちます。一方、ワーキングレジスタの内容に文字コードが入っていれば、”0”を加算しても文字コードの値は変化しません。すなわち、表示する文字があればLCD_DATAというサブルーチンへジャンプして表示し、終了すれば次の段階のTEXT_CLEARへジャンプする条件分岐を行っています。

(31)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(32)テーブルポインタ +1
次の文字表示を行うためテーブルポインタの値を+1します。テーブルポインタの値は、プログラムカウンタにテーブルポインタの値(OFFSET分)を足し合わせることで、表示文字が記載されたテーブルの位置関係を指し示すようになっています。

(33)ROW_2 のラベルへ戻り繰り返す
次の文字表示を行うため、ROW_2 のラベルへ戻り繰り返します。

(34)表示クリア
液晶表示器の2行目まで文字表示の終了後、1行目に戻って繰り返し表示を行うため、表示をクリアします。
このインストラクションの詳細については、表示クリアを参照

(35)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(36)WAIT(1秒)
液晶表示器の画面の変化が、人間の目で分かるように1秒間のウエイトを入れました。TIME1Sというラベルの付いたサブルーチンへジャンプします。

(37)テキスト文字を繰り返し表示する
最初から文字表示を行うため、TEXT_OUT1のラベルへ戻り繰り返します。


(38)TABLEの定義(PC+OFFSET相当のデータを持って戻る)
    PC+OFFSET

データテーブルのサブルーチンに来ると、プログラムカウンタに、Wregの値(オフセット)が加算されます。その加算結果をプログラムカウンタとしますので、そのテーブルポインタ(アドレス)で指定されたデータを示すようになります。

ADDWF   PCL,F ;プログラムカウンタに、Wregの値(オフセット)を加算し、
             その加算結果をプログラムカウンタする。

(39)液晶表示器の初期化サブルーチン
詳細はインストラクションによる初期設定をご覧ください。


(40)WAIT(10ms)
   WAIT(10ms) 10ms×2=20msを確保(15ms以上)

液晶表示器の電源が4.5V以上に達してから、15ms以上のウエイトを入れます。ここでは10msのサブルーチンへ2回ジャンプすることで、20msを確保しています。

(41)ファンクションセット(8bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(42)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(43)WAIT(10ms)を確保(4.1ms以上)
上記のインストラクションの実行後、4.1ms以上のウエイトを入れます。ここでは10msのサブルーチンへジャンプすることで、10msを確保しています。

(44)ファンクションセット(8bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(45)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(46)WAIT(100μs)
上記のインストラクションの実行後、100μs以上のウエイトを入れます。ここでは100μsのサブルーチンへジャンプすることで、100μsを確保しています。

(47)ファンクションセット(8bitモードに設定)
このインストラクションの詳細については、ファンクションセットを参照

(48)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(49)WAIT(100μs)
上記のインストラクションの実行後、100μs以上のウエイトを入れます。ここでは100μsのサブルーチンへジャンプすることで、100μsを確保しています。

(50)ファンクションセット(8bitモード,1/16デューティ,5×7ドット)
このインストラクションの詳細については、ファンクションセットを参照

(51)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(52)ここからBFチェックができます
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSYというラベルの付いたサブルーチンへジャンプします。

(53)表示オフ
液晶表示器の初期化として表示をオフします。 このインストラクションの詳細については、表示オン/オフコントロールを参照

(54)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(55)BFチェック
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSYというラベルの付いたサブルーチンへジャンプします。

(56)表示クリア
液晶表示器の初期化として表示をクリアします。 このインストラクションの詳細については、表示クリアを参照

(57)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(58)BFチェック
上記のインストラクションが完了したかどうか確認のため、 Busy Flagのチェックをします。LCD_BUSYというラベルの付いたサブルーチンへジャンプします。

(59)エントリーモードセット
   アドレスを+1し、カーソルは右移動,表示シフトはしない)

液晶表示器の初期化としてエントリーモードをセットします。 このインストラクションの詳細については、エントリーモードセットを参照

(60)液晶表示器へコマンド出力
上記のインストラクションを実行させるため、液晶表示器へコマンドを出力します。LCD_CMDというラベルの付いたサブルーチンへジャンプします。

(61)液晶表示器へコマンドを出力するサブルーチン
インストラクションを実行させるためのサブルーチンです。各信号の制御関係については、制御信号のタイムチャートを参照してください。

(62)DB0〜DB7(データバスの設定)
インストラクションの設定データをRBポートに出力します。

(63)R/W = 0 (書き込みモードに設定)
リード/ライト選択信号(H=読み込み,L=書き込み)を書き込みモードに設定します。

(64)RS = 0 (コマンドモードに設定)
レジスタ選択信号、すなわちコマンド/データ選択(H=データ,L=コマンド)をコマンドモードに設定します。

(65)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(66)Eのパルス幅を220ns以上確保するためのダミー命令
動作起動信号のパルス幅を220ns以上に確保するためにNOP命令を入れておきます。連続してON,OFFした場合、PIC命令の1サイクルの実行時間は、1サイクル実行時間=4/クロック周波数となっていますので、クロック周波数が20MHz(50ns)の場合は、4/20MHz=4*50ns=200nsとなります。1命令文で連続してON,OFFした場合、20MHzのクロック周波数では、十分なパルス幅を確保できません。したがって、間にNOP命令などを挿入して十分なパルス幅をとる必要があります。

(67)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(68)液晶表示器へデータを出力するサブルーチン
インストラクションを実行させるためのサブルーチンです。各信号の制御関係については、制御信号のタイムチャートを参照してください。

(69)DB0〜DB7(データバスの設定)
インストラクションの設定データをRBポートに出力します。

(70)R/W = 0 (書き込みモードに設定)
リード/ライト選択信号(H=読み込み,L=書き込み)を書き込みモードに設定します。

(71)RS = 1 (データモードに設定)
レジスタ選択信号、すなわちコマンド/データ選択(H=データ,L=コマンド)をデータモードに設定します。

(72)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(73)Eのパルス幅を220ns以上確保するためのダミー命令
動作起動信号のパルス幅を220ns以上に確保するためにNOP命令を入れておきます。

(74)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(75)ビジーチェック(BF)を行うサブルーチン
以前に受けたインストラクションによって、モジュールが内部動作中である間はループを繰り返し、インストラクションが完了するとメインルーチンへ戻るサブルーチンです。なお、制御信号の関係については、制御信号のタイムチャート(読み込み時)を参照してください。

(76)Bank 1 へ切替
RBポートを入力モードに設定するために、Bank1へ切り替えます。

(77)入力モードにPortB を設定
TRISBレジスタの全ビットを”1”にすることで入力モードに設定します。

(78)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。

(79)RS = 0 (コマンドモードに設定)
レジスタ選択信号、すなわちコマンド/データ選択(H=データ,L=コマンド)をコマンドモードに設定します。

(80)R/W = 1 (読み込みモードに設定)
リード/ライト選択信号(H=読み込み,L=書き込み)を読み込みモードに設定します。

(81)E = 1 (動作起動信号の設定:Hでストローブ)
動作起動信号をHレベルにして、各データをストローブします。

(82)DDRAMからのデータの読み出し
RBポートからDDRAMのデータを読み出します。

(83)E = 0 (動作起動信号の設定:Lに戻す)
動作起動信号をLレベルにして、設定が完了します。

(84)読み込みデータをレジスタファイルに一時保存
DPDT変数にデータを格納しておきます。

(85)ビジーフラグのチェック(読み込みデータの7ビット目)
    BUSY_F=1のときLCD_BUSY間をループする
    BUSY_F=0のときループを抜ける

DPDT変数に格納されているデータの7ビット目がビジーフラグ(BF)です。このインストラクションの詳細については、ビジーフラグ/アドレス読み出しを参照してください。条件分岐は、BF=1のときループし、0のときループから抜け出るようになっています。

(86)R/W = 0 (書き込みモードに設定)
(80)でリード/ライト選択信号(H=読み込み,L=書き込み)を書き込みにモードに戻しておきます。

(87)Bank 1 へ切替
RBポートを出力モードに戻しておくために、Bank1へ切り替えます。

(88)出力モードにPortB を設定
TRISBレジスタの全ビットを”0”にすることで出力モードに設定します。

(89)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。


ポートの誤動作防止について
ここがポイント
BSF,BCFなどのビット操作命令で、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる
ここは、(63)と(64)と(65)の各コマンド間、及び(70)と(71)と(72)の各コマンド間、及び(79)と(80)と(81)の各コマンド間のように、BSF,BCFなどのビット操作命令により同一ポートを続けて設定していると、ポートが誤動作をすることがあります。BSF,BCFなどのビット操作命令は、一度ポートレジスタのすべてのビットの状態を読み込み、指定ビットのみを変更して再度ポートレジスタに上書きするという操作がされます。すなわち、最初の命令 たとえば(63)の出力がなされ、次の命令(64)が出力される前に、一度入力動作があるのです。最初の命令の出力と次の命令の入力動作の間は、1クロック分しかなく、20MHzクロックの場合にはわずかに50nsecです。出力ピンの負荷に何らかの容量成分があると、信号の立ち上がりや立ち下がりが遅れるため、最初の命令の出力が完全に落ち着く前に次の命令で読み込みを実行してしまうため誤動作が発生しやすくなります。この対策としては、ビット操作命令で連続して同じポートに出力する場合には、間にNOP命令など他の命令を最低1個挿入するようにします。

;***********************************************************
; 液晶表示器へコマンドを出力するサブルーチン
;***********************************************************
LCD_CMD
    MOVWF   PORTB
    BCF    PORTA,RW
    
NOP
    BCF    PORTA,RS
    
NOP
    BSF    PORTA,E
    NOP
    BCF    PORTA,E
    RETURN
;(61)液晶表示器へコマンドを出力するサブルーチン
;(62)DB0〜DB7(データバスの設定)
;(63)R/W = 0 (書き込みモードに設定)
; 誤動作防止のダミー命令
;(64)RS = 0 (コマンドモードに設定)
; 誤動作防止のダミー命令
;(65)E = 1 (動作起動信号の設定:Hでストローブ)
;(66)Eのパルス幅を220ns以上確保するためのダミー命令
;(67)E = 0 (動作起動信号の設定:Lに戻す)

;***********************************************************
; 液晶表示器へデータを出力するサブルーチン
;***********************************************************
LCD_DATA
    MOVWF   PORTB
    BCF    PORTA,RW
    NOP
    BSF    PORTA,RS
    NOP
    BSF    PORTA,E
    NOP
    BCF    PORTA,E
    RETURN
;(68)液晶表示器へデータを出力するサブルーチン
;(69)DB0〜DB7(データバスの設定)
;(70)R/W = 0 (書き込みモードに設定)
; 誤動作防止のダミー命令
;(71)RS = 1 (データモードに設定)
; 誤動作防止のダミー命令
;(72)E = 1 (動作起動信号の設定:Hでストローブ)
;(73)Eのパルス幅を220ns以上確保するためのダミー命令
;(74)E = 0 (動作起動信号の設定:Lに戻す)
;
;***********************************************************
; ビジーチェック(BF)を行うサブルーチン
;***********************************************************
LCD_BUSY
    BSF    STATUS,RP0
    MOVLW   0FFH
    MOVWF   TRISB
    BCF    STATUS,RP0
    BCF    PORTA,RS
    NOP
    BSF    PORTA,RW
    NOP
    BSF    PORTA,E
    MOVF   PORTB,W
    BCF    PORTA,E
    MOVWF   DPDT
    BTFSC   DPDT,BUSY_F
    GOTO   LCD_BUSY

    BCF    PORTA,RW
    BSF    STATUS,RP0
    MOVLW   0H
    MOVWF   TRISB
    BCF    STATUS,RP0
    RETURN
;(75)ビジーチェック(BF)を行うサブルーチン
;(76)Bank 1 へ切替
;(77)入力モードに
;   PortB を設定
;(78)Bank 0 へ戻す
;(79)RS = 0 (コマンドモードに設定)
; 誤動作防止のダミー命令
;(80)R/W = 1 (読み込みモードに設定)
; 誤動作防止のダミー命令
;(81)E = 1 (動作起動信号の設定:Hでストローブ)
;(82)DDRAMからのデータの読み出し
;(83)E = 0 (動作起動信号の設定:Lに戻す)
;(84)読み込みデータをレジスタファイルに一時保存
;(85)ビジーフラグのチェック(読み込みデータの7ビット目)
;   BUSY_F=1のときLCD_BUSY間をループする
;   BUSY_F=0のときループを抜ける
;(86)R/W = 0 (書き込みモードに設定)
;(87)Bank 1 へ切替
;(88)出力モードに
;   PortB を設定
;(89)Bank 0 へ戻す
;



<項目>液晶表示の動作確認
図4に(a)16文字×2行の液晶表示器での表示例、(b)20文字×4行の液晶表示器での表示例を示します。表示動作は、左上から「SPECTRUMホームヘ゜ーシ゛」と1秒おきに順に表示し、次に2行目に移って「0123456789ABCDEF」と順に表示していきます。表示が終わるとクリアされて最初からまた表示を繰り返します。
(注)図4の表示例は、2行目の「C」が表示された段階で撮影されたものです。

16文字×2行の液晶表示器の例 20文字×4行の液晶表示器の例
図4(a).16文字×2行の
液晶表示器の例
図4(b).20文字×4行の
液晶表示器の例 




<戻る> <次ページへ>
<TOPページへ>